<template>
  <je-modal
    v-model:visible="visibleModule"
    width="1200"
    height="80%"
    class="roledeptpost-selector"
    :title="stateData.title"
    :resize="false"
    :maximizable="false"
    cancel-button
    :ok-button="addModule"
    @close="cancelModal"
  >
    <div class="context">
      <div class="tree-div">
        <je-panel>
          <je-panel-item region="top" v-bind="options.top">
            <div class="header">{{ stateData.header }}</div>
          </je-panel-item>
          <je-panel-item>
            <je-tree
              ref="treeview"
              class="treeView"
              height="100%"
              :search="{ style: 'height:40px;' }"
              :draggable="{
                group: { name: 'group', put: false, pull: 'clone' },
                sort: false,
              }"
              :loading="stateData.loading"
              size="mini"
              :data="stateData.treeData"
            >
            </je-tree>
          </je-panel-item>
          <je-panel-item region="bottom" v-bind="options.bottom">
            <div
              style="border-left: 1px solid #e6e6e6; border-right: 1px solid #e6e6e6; height: 100%"
            >
              <je-checkbox v-model:checked="stateData.cascadeDrag">{{
                $t('RoledeptpostSelector.cascadeDrag')
              }}</je-checkbox>
            </div>
          </je-panel-item>
        </je-panel>
      </div>
      <div class="checked-div">
        <je-panel>
          <je-panel-item region="top" v-bind="options.checkedTop">
            <div class="header">{{ stateData.selectHeader }}</div>
            <je-search
              v-model:value="stateData.searchValue"
              label-field="text"
              @search="onSearch"
              @select="onSelect"
            ></je-search>
          </je-panel-item>
          <je-panel-item>
            <div ref="listRef" class="list">
              <div
                v-for="item in checkedData"
                :key="item.resourceId"
                :class="`item is--draggable ${
                  item.resourceId == stateData.checkedId ? 'select' : ''
                }`"
                :data-rowData="encode(item)"
                @mouseover="stateData.showId = item.resourceId"
                @mouseleave="stateData.showId = ''"
                @click.stop="checkTreeNode(item.resourceId)"
              >
                <i style="margin-right: 6px" :class="item.resourceIcon"></i> {{ item.resourceName }}

                <i
                  v-show="item.resourceId == stateData.showId"
                  class="delete fal fa-times"
                  @click.stop="removeOne(item)"
                ></i>
              </div>
            </div>
          </je-panel-item>
          <je-panel-item region="bottom" v-bind="options.bottom">
            <div style="padding-right: 8px; height: 100%">
              <span class="remove" @click="removeALL">{{
                $t('RoledeptpostSelector.removeAll')
              }}</span>
            </div>
          </je-panel-item>
        </je-panel>
      </div>
      <div class="form-div">
        <je-panel>
          <je-panel-item region="top" v-bind="options.top">
            <div class="header filter">{{ $t('RoledeptpostSelector.filterHeader') }}</div>
          </je-panel-item>
          <je-panel-item style="border-left: 1px solid #e6e6e6; border-right: 1px solid #e6e6e6">
            <je-form
              :model="stateData.formState"
              :colon="false"
              :label-col="labelCol"
              :wrapper-col="wrapperCol"
              size="small"
              autocomplete="off"
            >
              <je-form-item :label="$t('RoledeptpostSelector.company')" name="company">
                <je-switch v-model:value="stateData.formState.company" mode="checkbox" />
                <span class="prompt">{{
                  props.checkedRow.type == 'roleConfig'
                    ? $t('RoledeptpostSelector.companyContextRole')
                    : $t('RoledeptpostSelector.companyContext')
                }}</span>
              </je-form-item>

              <je-form-item
                :label="$t('RoledeptpostSelector.companymanagerdept')"
                name="companySupervision"
              >
                <je-switch v-model:value="stateData.formState.companySupervision" mode="checkbox" />
                <span class="prompt">{{
                  props.checkedRow.type == 'roleConfig'
                    ? $t('RoledeptpostSelector.companymanagerroleContext')
                    : $t('RoledeptpostSelector.companymanagerdeptContext')
                }}</span>
              </je-form-item>

              <je-form-item :label="$t('RoledeptpostSelector.dept')" name="dept">
                <je-switch v-model:value="stateData.formState.dept" mode="checkbox" />
                <span class="prompt">{{
                  props.checkedRow.type == 'roleConfig'
                    ? $t('RoledeptpostSelector.roleContext')
                    : $t('RoledeptpostSelector.deptContext')
                }}</span>
              </je-form-item>

              <je-form-item :label="$t('RoledeptpostSelector.deptall')" name="deptAll">
                <je-switch v-model:value="stateData.formState.deptAll" mode="checkbox" />
                <span class="prompt">{{ $t('RoledeptpostSelector.deptallContext') }}</span>
              </je-form-item>

              <je-form-item :label="$t('RoledeptpostSelector.zsld')" name="directLeader">
                <je-switch v-model:value="stateData.formState.directLeader" mode="checkbox" />
                <span class="prompt">{{
                  props.checkedRow.type == 'roleConfig'
                    ? $t('RoledeptpostSelector.zsldContextRole')
                    : $t('RoledeptpostSelector.zsldContext')
                }}</span>
              </je-form-item>

              <je-form-item :label="$t('RoledeptpostSelector.head')" name="deptLeader">
                <je-switch v-model:value="stateData.formState.deptLeader" mode="checkbox" />
                <span class="prompt">{{
                  props.checkedRow.type == 'roleConfig'
                    ? $t('RoledeptpostSelector.headContextRole')
                    : $t('RoledeptpostSelector.headContext')
                }}</span>
              </je-form-item>

              <je-form-item :label="$t('RoledeptpostSelector.jghead')" name="supervisionLeader">
                <je-switch v-model:value="stateData.formState.supervisionLeader" mode="checkbox" />
                <span class="prompt">{{
                  props.checkedRow.type == 'roleConfig'
                    ? $t('RoledeptpostSelector.jgheadContextRole')
                    : $t('RoledeptpostSelector.jgheadContext')
                }}</span>
              </je-form-item>

              <je-form-item name="sql">
                <template #label>
                  <i class="conditionicon fas fa-question-circle" @click="clickIcon()" />
                  {{ $t('RoledeptpostSelector.userWhereSql') }}
                </template>
                <je-textarea v-model:value="stateData.formState.sql" :rows="6" />
              </je-form-item>

              <je-form-item :label="$t('RoledeptpostSelector.whereSqlContext')" name="sqlRemarks">
                <je-textarea v-model:value="stateData.formState.sqlRemarks" :rows="6" />
              </je-form-item>
            </je-form>
          </je-panel-item>
        </je-panel>
      </div>
    </div>
    <Explain
      v-if="explainType"
      :modal-context="modalContext"
      width="500px"
      @closEexplain="closEexplain"
    />
  </je-modal>
</template>
<script>
  import { defineComponent, watch, ref, onMounted, reactive, nextTick } from 'vue';
  import { Input, Modal, Form, Panel, Tree, Checkbox, Search, Switch } from '@jecloud/ui';
  import { loadTree } from '@/api/index';
  import { cloneDeep, encode, pinyin, decode } from '@jecloud/utils';
  import Sortable from 'sortablejs';
  import Explain from '@/components/explain/index.vue';

  export default defineComponent({
    name: 'RoledeptpostSelector',
    components: {
      JeModal: Modal,
      JePanel: Panel,
      JePanelItem: Panel.Item,
      JeTree: Tree,
      JeCheckbox: Checkbox,
      JeSearch: Search,
      JeForm: Form,
      JeFormItem: Form.Item,
      JeTextarea: Input.TextArea,
      JeSwitch: Switch,
      Explain,
    },
    props: {
      checkedRow: {
        type: Object,
        default: () => {
          return {};
        },
      },
      funcInfo: {
        type: Object,
        default: () => {
          return {};
        },
      },
    },
    emits: ['setModalType'],
    setup(props, { emit }) {
      //树对象
      const treeview = ref(null);
      //弹窗是否开启
      const visibleModule = ref(true);
      //选中的数据
      const checkedData = ref([]);
      //数据集
      const stateData = reactive({
        searchValue: '',
        title: '',
        header: '',
        selectHeader: '',
        treeData: [],
        showId: '',
        checkedId: '',
        loading: false,
        cascadeDrag: false,
        formState: {
          company: '0',
          companySupervision: '0',
          dept: '0',
          deptAll: '0',
          directLeader: '0',
          deptLeader: '0',
          supervisionLeader: '0',
          sql: '',
          sqlRemarks: '',
        },
      });
      const listRef = ref(null);
      let mySortable = null;
      onMounted(() => {
        getTitle(props.checkedRow);
        loadTreeData(props.checkedRow);
        constgetDeconstructionData(props.checkedRow);
        setTimeout(() => {
          let g2 = listRef.value || document.getElementsByClassName('list')[0];
          let ops2 = {
            animation: 300,
            delay: 0,
            sort: true,
            forceFallback: true, // 不使用H5原生拖动
            group: { name: 'group' }, // 拖动组
            onEnd: ({ item, oldIndex, newIndex }) => {
              const rowData = decode(item.getAttribute('data-rowData'));
              const newDatas = cloneDeep(checkedData.value);
              if (oldIndex != newIndex) {
                newDatas.splice(oldIndex, 1);
                newDatas.splice(newIndex, 0, rowData);
                checkedData.value = newDatas;
              }
            },
            onAdd: ({ item, newIndex }) => {
              const rowId = item.getAttribute('rowId');
              const row = treeview.value.getRowById(rowId);
              drop({ row, newIndex });
            },
          };
          mySortable = Sortable.create(g2, ops2);
        }, 100);
      });

      //拖拽方法
      const drop = function ({ row, newIndex }) {
        // 只能拖入角色
        if (props.checkedRow.type == 'roleConfig' && !stateData.cascadeDrag) {
          if (row.nodeInfoType == 'folder') {
            Modal.alert('请拖入角色！', 'error');
            return false;
          }
        }
        // 只能拖入部门
        if (props.checkedRow.type == 'departmentConfig' && !stateData.cascadeDrag) {
          if (row.nodeInfoType == 'company') {
            Modal.alert('请拖入部门！', 'error');
            return false;
          }
        }
        //和已选的数据不能重复
        if (
          checkedData.value.length > 0 &&
          checkedData.value.filter((item) => item.resourceId == row.id).length > 0
        ) {
          return false;
        }
        //是否是级联拖拽
        if (stateData.cascadeDrag) {
          const datas = getNodeChildData(row);
          if (datas.length > 0) {
            const newDatas = cloneDeep(checkedData.value);
            newDatas.splice(newIndex, 0, ...datas);
            const dats = [];
            //数据去重
            newDatas.forEach((item) => {
              if (dats.filter((_item) => _item.resourceId == item.resourceId).length <= 0) {
                dats.push(item);
              }
            });
            checkedData.value = dats;
          }
        } else {
          const data = {
            resourceCode: row.code,
            resourceId: row.id,
            resourceName: row.text,
            resourceIcon: row.icon || 'fal fa-file',
          };
          checkedData.value.splice(newIndex, 0, data);
        }
      };

      //获得节点下面所有子节点的数据并进行封装
      const getNodeChildData = (node) => {
        //如果没有子节点
        const datas = [];
        //如果有子节点
        const getChildData = (childNode) => {
          //角色不能拖入文件夹
          childNode.forEach((item) => {
            if (
              (props.checkedRow.type == 'roleConfig' && item.nodeInfoType != 'folder') ||
              (props.checkedRow.type == 'departmentConfig' && item.nodeInfoType != 'company')
            ) {
              datas.push({
                resourceCode: item.code,
                resourceId: item.id,
                resourceName: item.text,
                resourceIcon: item.icon || 'fal fa-file',
              });
            }
            if (item.children.length > 0) {
              getChildData(item.children);
            }
          });
        };
        //角色不能拖入文件夹
        if (
          (props.checkedRow.type == 'roleConfig' && node.nodeInfoType != 'folder') ||
          (props.checkedRow.type == 'departmentConfig' && node.nodeInfoType != 'company')
        ) {
          datas.push({
            resourceCode: node.code,
            resourceId: node.id,
            resourceName: node.text,
            resourceIcon: node.icon || 'fal fa-file',
          });
        }

        getChildData(node.children);

        return datas;
      };

      //获得modal的title
      const getTitle = (data) => {
        let text = '',
          header = '',
          selectHeader = '';
        if (data.type == 'departmentConfig') {
          text = '指定部门';
          header = '部门树';
          selectHeader = '已选部门';
        } else {
          text = '指定角色';
          header = '角色树';
          selectHeader = '已选角色';
        }
        stateData.title = text;
        stateData.header = header;
        stateData.selectHeader = selectHeader;
      };

      //解构父节点传入的数据
      const constgetDeconstructionData = (data) => {
        //选择数据赋值
        if (data.resourceId && data.resourceId.split(',').length > 0) {
          const selectData = [],
            resourceCodes = data.resourceCode.split(','),
            resourceIds = data.resourceId.split(','),
            resourceNames = data.resourceName.split(','),
            resourceIcons = data.resourceIcon.split(',');
          resourceCodes.forEach((item, index) => {
            selectData.push({
              resourceCode: item,
              resourceId: resourceIds[index],
              resourceName: resourceNames[index],
              resourceIcon: resourceIcons[index],
            });
          });
          if (resourceCodes.length > 0) {
            checkedData.value = selectData;
          }
        }
        //权限表单赋值
        Object.assign(stateData.formState, data.permission);
      };

      //监听父组件传来的数据
      watch(
        () => props.checkedRow,
        (newValue) => {
          getTitle(newValue);
          loadTreeData(newValue);
          constgetDeconstructionData(newValue);
        },
        { deep: true },
      );

      //点击确定方法
      const addModule = ({ $modal, button }) => {
        if (checkedData.value.length > 0) {
          emit('setModalType', {
            type: 'RoledeptpostSelector',
            btnType: 'save',
            data: { selectData: checkedData.value, permission: stateData.formState },
          });
          $modal.close();
        } else {
          Modal.alert('请选择数据', 'info');
        }

        return false;
      };

      //弹窗关闭方法
      const cancelModal = () => {
        visibleModule.value = false;
        emit('setModalType', { type: 'RoledeptpostSelector', btnType: 'close' });
      };

      //初始化tree数据
      const loadTreeData = (row) => {
        stateData.treeData = [];
        stateData.loading = true;
        const params = {
          excludes: 'checked',
          onlyItem: true,
          strData: encode([
            {
              ddCode: row.type == 'departmentConfig' ? 'JE_RBAC_DEPTTREE' : 'JE_RBAC_ROLETREE',
              ddName: '规则配置',
              rootId: '',
              async: false,
              params: {},
              j_query: { custom: [], order: [], _types: [] },
              nodeInfo: '',
            },
          ]),
          node: 'ROOT',
        };
        loadTree(params)
          .then((data) => {
            stateData.treeData = data;
            stateData.loading = false;
            if (row.type == 'departmentConfig') {
              const rootData = data[0];
              treeview.value && treeview.value.setTreeExpand(rootData, true);
            }
          })
          .catch((e) => {
            Modal.alert(e.message, 'error');
          });
      };

      //移除已选数据
      const removeALL = () => {
        checkedData.value = [];
      };

      //删除一个
      const removeOne = (data) => {
        checkedData.value = checkedData.value.filter((item) => item.resourceId != data.resourceId);
      };

      //选中tree的节点
      const checkTreeNode = (id) => {
        stateData.checkedId = id;
        const row = treeview.value.getRowById(id);
        if (row) {
          treeview.value.setTreeExpand4Path({ row, expand: true }).then((row) => {
            treeview.value.setSelectRow(row);
            treeview.value.scrollToRow(row);
          });
        }
      };
      // 节点过滤函数
      const filter = (item, keyword) => {
        const _word = item.resourceName?.toLocaleLowerCase() ?? '';
        const pinyinText = pinyin(_word, 'pinyin');
        if (_word.includes(keyword) || pinyinText.includes(keyword)) {
          return true;
        }
        return false;
      };
      // 查询关键字
      const onSearch = (keyword, resolve) => {
        if (checkedData.value.length === 0) return false;
        let items = [];
        keyword = keyword.toLocaleLowerCase();
        checkedData.value.forEach((item) => {
          if (filter(item, keyword)) {
            items.push({
              value: item.resourceName,
              text: item.resourceName,
              key: item.resourceId,
              row: item,
            });
          }
        });
        resolve(items);
      };
      //搜索下拉选中
      const onSelect = (val, option) => {
        stateData.searchValue = val;
        checkTreeNode(option.key);
      };
      const explainType = ref(false);
      const modalContext = ref('');
      const clickIcon = () => {
        modalContext.value =
          '以and开头，拼接账号部门视图（JE_RBAC_VACCOUNTDEPT）中的字段，支持变量写法，例如：系统变量{@USER_ID@}、或取表单字段{FIELD_CODE}';

        explainType.value = true;
      };

      //弹窗关闭回调
      const closEexplain = () => {
        explainType.value = false;
      };

      return {
        checkTreeNode,
        removeOne,
        removeALL,
        addModule,
        cancelModal,
        treeview,
        visibleModule,
        stateData,
        checkedData,
        onSearch,
        onSelect,
        props,
        options: {
          top: { size: 40 },
          checkedTop: { size: 80 },
          bottom: {
            size: 30,
            style: {
              textAlign: 'right',
              borderColor: '#e6e6e6',
            },
          },
        },
        listRef,
        drop,
        labelCol: {
          span: 7,
        },
        wrapperCol: {
          span: 17,
        },
        explainType,
        closEexplain,
        modalContext,
        clickIcon,
        encode,
      };
    },
  });
</script>

<style lang="less" scoped>
  .roledeptpost-selector {
    .context {
      border-bottom: 1px solid #e6e6e6;
      display: flex;
      height: 100%;
      .tree-div {
        position: relative;
        width: 30%;
        height: 100%;
        .header {
          border-top: 1px solid #e6e6e6;
          border-left: 1px solid #e6e6e6;
          border-right: 1px solid #e6e6e6;
        }
        .treeView {
          height: 100%;
        }
      }
      .checked-div {
        //border-left: 1px solid #e6e6e6;
        // border-right: 1px solid #e6e6e6;
        width: 30%;
        height: 100%;
        .header {
          border-top: 1px solid #e6e6e6;
        }
        .list {
          height: 100%;
          //border-left: 1px solid #e6e6e6;
          overflow-x: auto;
          .select {
            background: #f2f2f2;
            color: #006ed7;
          }
          div {
            height: 32px;
            line-height: 32px;
            padding: 0 12px;
            font-size: 14px;
            position: relative;
            cursor: pointer;
            .delete {
              position: absolute;
              right: 10px;
              top: 9px;
            }
            &:hover {
              background: #f2f2f2;
              color: #006ed7;
            }
          }
        }
        .remove {
          cursor: pointer;
          color: #b8741a;
        }
      }
      .form-div {
        width: 40%;
        height: 100%;
        .header {
          border: 1px solid #e6e6e6;
        }
      }
      .header {
        background: #f7f9fc;
        height: 40px;
        line-height: 40px;
        text-align: center;
        font-size: 14px;
      }
      .filter {
        border-bottom: 1px solid #e6e6e6;
      }
    }
  }
</style>

<style lang="less">
  .roledeptpost-selector {
    .ant-col.ant-form-item-control {
      min-height: auto !important;
    }
    .je-tree-search-wrapper .ant-input-affix-wrapper.ant-select-selection-search-input {
      height: 40px !important;
      border-radius: 0;
    }
    .ant-select-selector .ant-input-affix-wrapper.ant-select-selection-search-input {
      height: 40px;
      border-radius: 0;
    }
    .treeView .je-panel-item.je-panel-item-region-default {
      border-left: 1px solid #e6e6e6;
      border-right: 1px solid #e6e6e6;
    }
    .checked-div {
      .list {
        .je-tree-node-icon {
          margin: 0 12px;
        }
        .vxe-cell--tree-node {
          padding-left: 0 !important;
        }
        .vxe-tree--node-btn {
          display: none;
        }
      }
      .je-panel .je-panel-body .je-panel-wrapper .je-panel-item.je-panel-item-region-default {
        overflow: hidden;
      }
      .je-panel-item.je-panel-item-region-top {
        .je-search.ant-select-show-search {
          height: 40px;
          width: 100%;
          border-left: 0;
          border-right: 0;
          .ant-input-affix-wrapper.ant-select-selection-search-input {
            border-left: 0;
            border-right: 0;
            &:hover {
              border-left: 1px solid #5c8dff;
              border-right: 1px solid #5c8dff;
            }
          }
          .ant-input-affix-wrapper-focused.ant-select-selection-search-input {
            border-left: 1px solid #5c8dff;
            border-right: 1px solid #5c8dff;
          }
        }
      }
    }
  }
</style>
